﻿#if UNITY_EDITOR
//////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2014 Audiokinetic Inc. / All Rights Reserved
//
//////////////////////////////////////////////////////////////////////
#pragma warning disable 0168
using UnityEngine;
using UnityEditor;
using System;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
using System.Collections;
using System.Collections.Generic;

public class WwiseWWUBuilder
{
	static string	s_wwiseProjectPath	= AudioSetting.Instance.WwiseProjectDirectory;
	const string	s_progTitle			= "Populating Wwise Picker";
	int		m_currentWwuCnt 	= 0;
	int		m_totWwuCnt 		= 1;
    HashSet<string> m_WwuToProcess = new HashSet<string>();

    static string[] FoldersOfInterest = new string[] { "Events", "States", "Switches", "SoundBanks", "Master-Mixer Hierarchy", "Game Parameters", "Triggers" };
	
	public class AssetType
	{
        public string RootDirectoryName { get; set; }
        public string XmlElementName;
        public string ChildElementName;
        public WwiseObjectType Type = WwiseObjectType.None;
        public WwiseObjectType ChildType = WwiseObjectType.None;

        public static AssetType[] ScannedAssets
        {
            get { return _ScannedAssets; }
        }

        public static AssetType Create(string rootDirectoryName)
        {
            foreach (var asset in ScannedAssets)
                if (string.Equals(rootDirectoryName, asset.RootDirectoryName, System.StringComparison.OrdinalIgnoreCase))
                    return asset;

            return null;
        }

        private AssetType(string RootFolder, string XmlElemName, WwiseObjectType type)
        {
            RootDirectoryName = RootFolder;
            XmlElementName = XmlElemName;
            Type = type;
        }

        private static readonly AssetType[] _ScannedAssets = new AssetType[]
        {
            new AssetType("Master-Mixer Hierarchy", "AuxBus", WwiseObjectType.AuxBus),
            new AssetType("Events", "Event", WwiseObjectType.Event),
            new AssetType("SoundBanks", "SoundBank", WwiseObjectType.Soundbank),
            new AssetType("States", "StateGroup", WwiseObjectType.StateGroup) { ChildElementName = "State", ChildType = WwiseObjectType.State },
            new AssetType("Switches", "SwitchGroup", WwiseObjectType.SwitchGroup) { ChildElementName = "Switch", ChildType = WwiseObjectType.Switch },
            new AssetType("Game Parameters", "GameParameter", WwiseObjectType.GameParameter),
            new AssetType("Triggers", "Trigger", WwiseObjectType.Trigger),
            new AssetType("Virtual Acoustics", "AcousticTexture", WwiseObjectType.AcousticTexture),
        };
    }

    private static System.Collections.Generic.Dictionary<WwiseObjectType, System.Collections.Generic.List<AkWwiseProjectData.AkBaseInformation>> _WwiseObjectsToRemove
        = new System.Collections.Generic.Dictionary<WwiseObjectType, System.Collections.Generic.List<AkWwiseProjectData.AkBaseInformation>>();

    private static System.Collections.Generic.Dictionary<WwiseObjectType, System.Collections.Generic.List<AkWwiseProjectData.AkBaseInformation>> _WwiseObjectsToAdd
        = new System.Collections.Generic.Dictionary<WwiseObjectType, System.Collections.Generic.List<AkWwiseProjectData.AkBaseInformation>>();

    public static bool Populate(AudioSetting settings)
	{
		try
		{			
			if (String.IsNullOrEmpty(settings.WwiseProjectPath))
			{
				AkSoundEngine.LogError("WwiseUnity: Wwise project needed to populate from Work Units. Aborting.");
                return false;
			}

            string fullWwiseProjPath = settings.FullWwiseProjectPath;

            s_wwiseProjectPath = settings.WwiseProjectDirectory;

            if (!File.Exists(fullWwiseProjPath))
            {
                AkSoundEngine.LogError(fullWwiseProjPath + " not found!");
                return false;
            }

            WwiseWWUBuilder builder = new WwiseWWUBuilder();
            if (!builder.GatherModifiedFiles(true))
            {
                AkSoundEngine.LogWarning(fullWwiseProjPath + " not changed!");
                return false;
            }

            builder.UpdateFiles();
            return true;
        }
        catch (Exception e)
		{
			AkSoundEngine.LogError(e.ToString());
			EditorUtility.ClearProgressBar(); 
		}
        return true;    //There was an error, assume that we need to refresh.
	}	
    
    public class FileInfo_CompareByPath : IComparer
    {
        int IComparer.Compare(object a, object b)
        {
            FileInfo wwuA = a as FileInfo;
            FileInfo wwuB = b as FileInfo;

            return wwuA.FullName.CompareTo(wwuB.FullName);
        }
    }

    bool GatherModifiedFiles(bool force = false)
    {
        _WwiseObjectsToRemove.Clear();
        _WwiseObjectsToAdd.Clear();

        var data = AkWwiseProjectInfo.GetData();
		if (data == null)
			return false;
        bool bChanged = false;
        int iBasePathLen = s_wwiseProjectPath.Length + 1;
        foreach (string dir in FoldersOfInterest)
        {            
            List<int> deleted = new List<int>();            
			ArrayList knownFiles = data.GetWwuListByString(dir);    
            int cKnownBefore = knownFiles.Count;

            DirectoryInfo di = null;
            FileInfo[] files = null;
            try
            {
                //Get all Wwus in this folder.
                di = new DirectoryInfo(Path.Combine(s_wwiseProjectPath, dir));
                files = di.GetFiles("*.wwu", SearchOption.AllDirectories);                
            }
            catch(Exception)
            {
                return false;
            }
            Array.Sort(files, new FileInfo_CompareByPath());

            //Walk both arrays
            int iKnown = 0;
            int iFound = 0;
            
            while (iFound < files.Length && iKnown < knownFiles.Count)
            {
                AkWwiseProjectData.WorkUnit workunit = knownFiles[iKnown] as AkWwiseProjectData.WorkUnit;
                string foundRelPath = files[iFound].FullName.Substring(iBasePathLen);
                switch(workunit.PhysicalPath.CompareTo(foundRelPath))
                {
                    case 0: 
                        {
                            //File was there and is still there.  Check the FileTimes.
                            if (force)
                            {
                                m_WwuToProcess.Add(files[iFound].FullName);
                                bChanged = true;
                            }
                            else
                            {
                                try
                                {
                                    DateTime lastParsed = workunit.LastTime;
                                    if (files[iFound].LastWriteTime > lastParsed)
                                    {
                                        //File has been changed!   
                                        //If this file had a parent, parse recursively the parent itself
                                        m_WwuToProcess.Add(files[iFound].FullName);
                                        bChanged = true;
                                    }
                                }
                                catch (Exception)
                                {
                                    //Access denied probably (file does exists since it was picked up by GetFiles).
                                    //Just ignore this file.
                                }
                            }
                            iFound++;
                            iKnown++;
                        }break;
                    case 1:
                        {                                
                            m_WwuToProcess.Add(files[iFound].FullName);                                
                            iFound++;
                        }break;
                    case -1:
                        {
                            //A file was deleted.  Can't process it now, it would change the array indices.                                
                            deleted.Add(iKnown);
                            iKnown++;
                        }break;
                }                    
            }

            //The remainder from the files found on disk are all new files.
            for (; iFound < files.Length; iFound++)                
                m_WwuToProcess.Add(files[iFound].FullName); 

            //All the remainder is deleted.  From the end, of course.
            if (iKnown < knownFiles.Count)
                knownFiles.RemoveRange(iKnown, knownFiles.Count - iKnown);                    

            //Delete those tagged.
            for (int i = deleted.Count - 1; i >= 0; i--)
                knownFiles.RemoveAt(deleted[i]); 
                
            bChanged |= cKnownBefore != knownFiles.Count;                                                                                   
        }
        return bChanged || m_WwuToProcess.Count > 0;
    }

    private bool createWorkUnit(string in_relativePath, string in_wwuType, string in_fullPath)
    {
        var ParentID = string.Empty;
        try
        {
            var reader = System.Xml.XmlReader.Create(in_fullPath);
            reader.MoveToContent();

            //We check if the current work unit has a parent and save its guid if its the case
            while (!reader.EOF && reader.ReadState == System.Xml.ReadState.Interactive)
            {
                if (reader.NodeType == System.Xml.XmlNodeType.Element && reader.Name.Equals("WorkUnit"))
                {
                    if (reader.GetAttribute("PersistMode").Equals("Nested"))
                        ParentID = reader.GetAttribute("OwnerID");
                    break;
                }

                reader.Read();
            }

            reader.Close();
        }
        catch (System.Exception e)
        {
            UnityEngine.Debug.Log("WwiseUnity: A changed Work unit wasn't found. It must have been deleted " + in_fullPath);
            return false;
        }

        if (!string.IsNullOrEmpty(ParentID))
        {
            var parentPhysicalPath = string.Empty;

            var list = AkWwiseProjectInfo.GetData().GetWwuListByString(in_wwuType);

            //search for the parent and save its physical path
            for (var i = 0; i < list.Count; i++)
            {
                if ((list[i] as AkWwiseProjectData.WorkUnit).Guid.Equals(ParentID))
                {
                    parentPhysicalPath = (list[i] as AkWwiseProjectData.WorkUnit).PhysicalPath;
                    UpdateWorkUnit(parentPhysicalPath, in_fullPath, in_wwuType, in_relativePath);
                    return true;
                }
            }

            //Not found.  Wait for it to load
            return false;
        }

        //Root Wwu
        UpdateWorkUnit(string.Empty, in_fullPath, in_wwuType, in_relativePath);
        return true;
    }

    void UpdateFiles()
    {
        m_totWwuCnt = m_WwuToProcess.Count;

        var iBasePathLen = s_wwiseProjectPath.Length + 1;
        var iUnprocessed = 0;
        while (m_WwuToProcess.Count - iUnprocessed > 0)
        {
            System.Collections.IEnumerator e = m_WwuToProcess.GetEnumerator();
            for (var i = 0; i < iUnprocessed + 1; i++)
                e.MoveNext();

            var fullPath = e.Current as string;
            var relPath = fullPath.Substring(iBasePathLen);
            var typeStr = relPath.Remove(relPath.IndexOf(System.IO.Path.DirectorySeparatorChar));
            if (!createWorkUnit(relPath, typeStr, fullPath))
                iUnprocessed++;
        }

        //Add the unprocessed directly.  This can happen if we don't find the parent WorkUnit.  
        //Normally, it should never happen, this is just a safe guard.
        while (m_WwuToProcess.Count > 0)
        {
            System.Collections.IEnumerator e = m_WwuToProcess.GetEnumerator();
            e.MoveNext();
            var fullPath = e.Current as string;
            var relPath = fullPath.Substring(iBasePathLen);
            var typeStr = relPath.Remove(relPath.IndexOf(System.IO.Path.DirectorySeparatorChar));
            UpdateWorkUnit(string.Empty, fullPath, typeStr, relPath);
        }

        foreach (var pair in _WwiseObjectsToAdd)
        {
            System.Collections.Generic.List<AkWwiseProjectData.AkBaseInformation> removeList = null;
            if (!_WwiseObjectsToRemove.TryGetValue(pair.Key, out removeList))
                continue;

            removeList.Sort(AkWwiseProjectData.AkBaseInformation.CompareByGuid);
            foreach (var info in pair.Value)
            {
                var index = removeList.BinarySearch(info, AkWwiseProjectData.AkBaseInformation.CompareByGuid);
                if (index >= 0)
                    removeList.RemoveAt(index);
            }
        }

        foreach (var pair in _WwiseObjectsToRemove)
        {
            var type = pair.Key;
            var childType = type == WwiseObjectType.StateGroup ? WwiseObjectType.State : WwiseObjectType.Switch;

            foreach (var info in pair.Value)
            {
                var groupValue = info as AkWwiseProjectData.GroupValue;
                // 				if (groupValue != null)
                // 					foreach (var value in groupValue.values)
                // 						WwiseObjectReference.DeleteWwiseObject(childType, value.Guid);
                // 
                // 				WwiseObjectReference.DeleteWwiseObject(type, info.Guid);
            }
        }

        UnityEditor.AssetDatabase.SaveAssets();
        UnityEditor.AssetDatabase.Refresh();
        UnityEditor.EditorUtility.ClearProgressBar();
    }


    class tmpData
    {
        public string                               valueName;
        public AkWwiseProjectData.PathElement       pathElem;
        public int                                  ID;
        public Guid                                 Guid;
    };

    class tmpData_CompareByName : IComparer
    {
        int IComparer.Compare(object a, object b)
        {
            tmpData AkInfA = a as tmpData;
            tmpData AkInfB = b as tmpData;

            return AkInfA.valueName.CompareTo(AkInfB.valueName);
        }
    }
    static tmpData_CompareByName s_comparetmpDataByName = new tmpData_CompareByName();

	void UpdateWorkUnit(string in_parentRelativePath, string in_wwuFullPath, string in_wwuType, string in_relativePath)
	{
        var wwuRelPath = in_parentRelativePath;

        var PathAndIcons = new System.Collections.Generic.LinkedList<AkWwiseProjectData.PathElement>();

        //We need to build the work unit's hierarchy to display it in the right place in the picker
        var currentPathInProj = string.Empty;
        while (!wwuRelPath.Equals(string.Empty))
        {
            //Add work unit name to the hierarchy
            var wwuName = System.IO.Path.GetFileNameWithoutExtension(wwuRelPath);
            currentPathInProj = System.IO.Path.Combine(wwuName, currentPathInProj);
            //Add work unit icon to the hierarchy
            PathAndIcons.AddFirst(new AkWwiseProjectData.PathElement(wwuName, WwiseObjectType.WorkUnit));

            //Get the physical path of the parent work unit if any
            var list = AkWwiseProjectInfo.GetData().GetWwuListByString(in_wwuType);
            var index = list.BinarySearch(new AkWwiseProjectData.WorkUnit { PhysicalPath = wwuRelPath });
            wwuRelPath = (list[index] as AkWwiseProjectData.WorkUnit).ParentPhysicalPath;
        }

        //Add physical folders to the hierarchy if the work unit isn't in the root folder
        var physicalPath = in_relativePath.Split(System.IO.Path.DirectorySeparatorChar);
        for (var i = physicalPath.Length - 2; i > 0; i--)
        {
            PathAndIcons.AddFirst(
                new AkWwiseProjectData.PathElement(physicalPath[i], WwiseObjectType.PhysicalFolder));
            currentPathInProj = System.IO.Path.Combine(physicalPath[i], currentPathInProj);
        }

        //Parse the work unit file
        RecurseWorkUnit(AssetType.Create(in_wwuType), new System.IO.FileInfo(in_wwuFullPath), currentPathInProj,
            in_relativePath.Remove(in_relativePath.LastIndexOf(System.IO.Path.DirectorySeparatorChar)), PathAndIcons,
            in_parentRelativePath);
    }

    private int RecurseWorkUnit(AssetType in_type, System.IO.FileInfo in_workUnit, string in_currentPathInProj,
        string in_currentPhysicalPath, System.Collections.Generic.LinkedList<AkWwiseProjectData.PathElement> in_pathAndIcons,
        string in_parentPhysicalPath = "")
    {
        m_WwuToProcess.Remove(in_workUnit.FullName);
        System.Xml.XmlReader reader = null;
        var wwuIndex = -1;
        try
        {
            //Progress bar stuff
            var msg = "Parsing Work Unit " + in_workUnit.Name;
            UnityEditor.EditorUtility.DisplayProgressBar(s_progTitle, msg, m_currentWwuCnt / (float)m_totWwuCnt);
            m_currentWwuCnt++;

            in_currentPathInProj =
                System.IO.Path.Combine(in_currentPathInProj, System.IO.Path.GetFileNameWithoutExtension(in_workUnit.Name));
            in_pathAndIcons.AddLast(new AkWwiseProjectData.PathElement(
                System.IO.Path.GetFileNameWithoutExtension(in_workUnit.Name), WwiseObjectType.WorkUnit));
            var WwuPhysicalPath = System.IO.Path.Combine(in_currentPhysicalPath, in_workUnit.Name);

            var wwu = ReplaceWwuEntry(WwuPhysicalPath, in_type, out wwuIndex);

            wwu.ParentPhysicalPath = in_parentPhysicalPath;
            wwu.PhysicalPath = WwuPhysicalPath;
            wwu.Guid = System.Guid.Empty;
            wwu.LastTime = System.IO.File.GetLastWriteTime(in_workUnit.FullName);

            reader = System.Xml.XmlReader.Create(in_workUnit.FullName);

            reader.MoveToContent();
            reader.Read();
            while (!reader.EOF && reader.ReadState == System.Xml.ReadState.Interactive)
            {
                if (reader.NodeType == System.Xml.XmlNodeType.Element && reader.Name.Equals("WorkUnit"))
                {
                    if (wwu.Guid.Equals(System.Guid.Empty))
                    {
                        var ID = reader.GetAttribute("ID");
                        try
                        {
                            wwu.Guid = new System.Guid(ID);
                        }
                        catch
                        {
                            UnityEngine.Debug.LogWarning("WwiseUnity: Error reading ID <" + ID + "> from work unit <" + in_workUnit.FullName + ">.");
                            throw;
                        }
                    }

                    var persistMode = reader.GetAttribute("PersistMode");
                    if (persistMode == "Reference")
                    {
                        // ReadFrom advances the reader
                        var matchedElement = System.Xml.Linq.XNode.ReadFrom(reader) as System.Xml.Linq.XElement;
                        var newWorkUnitPath =
                            System.IO.Path.Combine(in_workUnit.Directory.FullName, matchedElement.Attribute("Name").Value + ".wwu");
                        var newWorkUnit = new System.IO.FileInfo(newWorkUnitPath);

                        // Parse the referenced Work Unit
                        if (m_WwuToProcess.Contains(newWorkUnit.FullName))
                        {
                            RecurseWorkUnit(in_type, newWorkUnit, in_currentPathInProj, in_currentPhysicalPath, in_pathAndIcons,
                                WwuPhysicalPath);
                        }
                    }
                    else
                    {
                        // If the persist mode is "Standalone" or "Nested", it means the current XML tag
                        // is the one corresponding to the current file. We can ignore it and advance the reader
                        reader.Read();
                    }
                }
                else if (reader.NodeType == System.Xml.XmlNodeType.Element && reader.Name.Equals("AuxBus"))
                {
                    in_currentPathInProj = System.IO.Path.Combine(in_currentPathInProj, reader.GetAttribute("Name"));
                    in_pathAndIcons.AddLast(new AkWwiseProjectData.PathElement(reader.GetAttribute("Name"),
                        WwiseObjectType.AuxBus));
                    var isEmpty = reader.IsEmptyElement;
                    AddElementToList(in_currentPathInProj, reader, in_type, in_pathAndIcons, wwuIndex);

                    if (isEmpty)
                    {
                        in_currentPathInProj =
                            in_currentPathInProj.Remove(in_currentPathInProj.LastIndexOf(System.IO.Path.DirectorySeparatorChar));
                        in_pathAndIcons.RemoveLast();
                    }
                }
                // Busses and folders act the same for the Hierarchy: simply add them to the path
                else if (reader.NodeType == System.Xml.XmlNodeType.Element &&
                         (reader.Name.Equals("Folder") || reader.Name.Equals("Bus")))
                {
                    //check if node has children
                    if (!reader.IsEmptyElement)
                    {
                        // Add the folder/bus to the path
                        in_currentPathInProj = System.IO.Path.Combine(in_currentPathInProj, reader.GetAttribute("Name"));
                        if (reader.Name.Equals("Folder"))
                        {
                            in_pathAndIcons.AddLast(new AkWwiseProjectData.PathElement(reader.GetAttribute("Name"),
                                WwiseObjectType.Folder));
                        }
                        else if (reader.Name.Equals("Bus"))
                        {
                            in_pathAndIcons.AddLast(new AkWwiseProjectData.PathElement(reader.GetAttribute("Name"),
                                WwiseObjectType.Bus));
                        }
                    }

                    // Advance the reader
                    reader.Read();
                }
                else if (reader.NodeType == System.Xml.XmlNodeType.EndElement &&
                         (reader.Name.Equals("Folder") || reader.Name.Equals("Bus") || reader.Name.Equals("AuxBus")))
                {
                    // Remove the folder/bus from the path
                    in_currentPathInProj =
                        in_currentPathInProj.Remove(in_currentPathInProj.LastIndexOf(System.IO.Path.DirectorySeparatorChar));
                    in_pathAndIcons.RemoveLast();

                    // Advance the reader
                    reader.Read();
                }
                else if (reader.NodeType == System.Xml.XmlNodeType.Element && reader.Name.Equals(in_type.XmlElementName))
                {
                    // Add the element to the list
                    AddElementToList(in_currentPathInProj, reader, in_type, in_pathAndIcons, wwuIndex);
                }
                else
                    reader.Read();
            }

            // Sort the newly populated Wwu alphabetically
            SortWwu(in_type, wwuIndex);
        }
        catch (System.Exception e)
        {
            UnityEngine.Debug.LogError(e.ToString());
            wwuIndex = -1;
        }

        if (reader != null)
            reader.Close();

        in_pathAndIcons.RemoveLast();
        return wwuIndex;
    }

    private static void SortWwu(AssetType in_type, int in_wwuIndex)
    {
        switch (in_type.Type)
        {
            case WwiseObjectType.AuxBus:
                AkWwiseProjectInfo.GetData().AuxBusWwu[in_wwuIndex].List.Sort();
                break;

            case WwiseObjectType.Event:
                AkWwiseProjectInfo.GetData().EventWwu[in_wwuIndex].List.Sort();
                break;

            case WwiseObjectType.Soundbank:
                AkWwiseProjectInfo.GetData().BankWwu[in_wwuIndex].List.Sort();
                break;

            case WwiseObjectType.GameParameter:
                AkWwiseProjectInfo.GetData().RtpcWwu[in_wwuIndex].List.Sort();
                break;

            case WwiseObjectType.Trigger:
                AkWwiseProjectInfo.GetData().TriggerWwu[in_wwuIndex].List.Sort();
                break;

            case WwiseObjectType.AcousticTexture:
                AkWwiseProjectInfo.GetData().AcousticTextureWwu[in_wwuIndex].List.Sort();
                break;

            case WwiseObjectType.StateGroup:
                var stateList = AkWwiseProjectInfo.GetData().StateWwu[in_wwuIndex].List;
                stateList.Sort();
                foreach (var group in stateList)
                    if (group.values.Count > 0)
                        group.values.Sort();
                break;

            case WwiseObjectType.SwitchGroup:
                var switchList = AkWwiseProjectInfo.GetData().SwitchWwu[in_wwuIndex].List;
                switchList.Sort();
                foreach (var group in switchList)
                    if (group.values.Count > 0)
                        group.values.Sort();
                break;
        }
    }

    private static AkWwiseProjectData.WorkUnit CreateWorkUnit(WwiseObjectType type)
    {
        switch (type)
        {
            case WwiseObjectType.Event:
                return new AkWwiseProjectData.EventWorkUnit();

            case WwiseObjectType.StateGroup:
            case WwiseObjectType.SwitchGroup:
                return new AkWwiseProjectData.GroupValWorkUnit();

            case WwiseObjectType.AuxBus:
            case WwiseObjectType.Soundbank:
            case WwiseObjectType.GameParameter:
            case WwiseObjectType.Trigger:
            case WwiseObjectType.AcousticTexture:
                return new AkWwiseProjectData.AkInfoWorkUnit();
        }

        return null;
    }

    private static AkWwiseProjectData.WorkUnit ReplaceWwuEntry(string in_currentPhysicalPath, AssetType in_type, out int out_wwuIndex)
    {
        var list = AkWwiseProjectInfo.GetData().GetWwuListByString(in_type.RootDirectoryName);
        out_wwuIndex = list.BinarySearch(new AkWwiseProjectData.WorkUnit { PhysicalPath = in_currentPhysicalPath });
        var out_wwu = CreateWorkUnit(in_type.Type);

        if (out_wwuIndex < 0)
        {
            out_wwuIndex = ~out_wwuIndex;
            list.Insert(out_wwuIndex, out_wwu);
        }
        else
            list[out_wwuIndex] = out_wwu;

        return out_wwu;
    }

    private static void FlagForInsertion(AkWwiseProjectData.AkBaseInformation info, WwiseObjectType type)
    {
        if (!_WwiseObjectsToAdd.ContainsKey(type))
            _WwiseObjectsToAdd[type] = new System.Collections.Generic.List<AkWwiseProjectData.AkBaseInformation>();

        _WwiseObjectsToAdd[type].Add(info);

//         if (!AkUtilities.IsMigrating)
//             WwiseObjectReference.UpdateWwiseObject(type, info.Name, info.Guid);
    }

    private static void AddElementToList(string in_currentPathInProj, System.Xml.XmlReader in_reader, AssetType in_type,
        System.Collections.Generic.LinkedList<AkWwiseProjectData.PathElement> in_pathAndIcons, int in_wwuIndex)
    {
        switch (in_type.Type)
        {
            case WwiseObjectType.AuxBus:
            case WwiseObjectType.Event:
            case WwiseObjectType.Soundbank:
            case WwiseObjectType.GameParameter:
            case WwiseObjectType.Trigger:
            case WwiseObjectType.AcousticTexture:
                {
                    var name = in_reader.GetAttribute("Name");
                    var valueToAdd = in_type.Type == WwiseObjectType.Event ? new AkWwiseProjectData.Event() : new AkWwiseProjectData.AkInformation();
                    valueToAdd.Name = name;
                    valueToAdd.Guid = new System.Guid(in_reader.GetAttribute("ID"));
                    valueToAdd.PathAndIcons = new System.Collections.Generic.List<AkWwiseProjectData.PathElement>(in_pathAndIcons);

                    FlagForInsertion(valueToAdd, in_type.Type);

                    switch (in_type.Type)
                    {
                        case WwiseObjectType.AuxBus:
                            valueToAdd.Path = in_currentPathInProj;
                            break;

                        default:
                            valueToAdd.Path = System.IO.Path.Combine(in_currentPathInProj, name);
                            valueToAdd.PathAndIcons.Add(new AkWwiseProjectData.PathElement(name, in_type.Type));
                            break;
                    }

                    switch (in_type.Type)
                    {
                        case WwiseObjectType.AuxBus:
                            AkWwiseProjectInfo.GetData().AuxBusWwu[in_wwuIndex].List.Add(valueToAdd);
                            break;

                        case WwiseObjectType.Event:
                            AkWwiseProjectInfo.GetData().EventWwu[in_wwuIndex].List.Add(valueToAdd as AkWwiseProjectData.Event);
                            break;

                        case WwiseObjectType.Soundbank:
                            AkWwiseProjectInfo.GetData().BankWwu[in_wwuIndex].List.Add(valueToAdd);
                            break;

                        case WwiseObjectType.GameParameter:
                            AkWwiseProjectInfo.GetData().RtpcWwu[in_wwuIndex].List.Add(valueToAdd);
                            break;

                        case WwiseObjectType.Trigger:
                            AkWwiseProjectInfo.GetData().TriggerWwu[in_wwuIndex].List.Add(valueToAdd);
                            break;

                        case WwiseObjectType.AcousticTexture:
                            AkWwiseProjectInfo.GetData().AcousticTextureWwu[in_wwuIndex].List.Add(valueToAdd);
                            break;
                    }
                }

                in_reader.Read();
                break;

            case WwiseObjectType.StateGroup:
            case WwiseObjectType.SwitchGroup:
                {
                    var XmlElement = System.Xml.Linq.XNode.ReadFrom(in_reader) as System.Xml.Linq.XElement;
                    var ChildrenList = System.Xml.Linq.XName.Get("ChildrenList");
                    var ChildrenElement = XmlElement.Element(ChildrenList);
                    if (ChildrenElement != null)
                    {
                        var name = XmlElement.Attribute("Name").Value;
                        var valueToAdd = new AkWwiseProjectData.GroupValue
                        {
                            Name = name,
                            Guid = new System.Guid(XmlElement.Attribute("ID").Value),
                            Path = System.IO.Path.Combine(in_currentPathInProj, name),
                            PathAndIcons = new System.Collections.Generic.List<AkWwiseProjectData.PathElement>(in_pathAndIcons),
                        };
                        valueToAdd.PathAndIcons.Add(new AkWwiseProjectData.PathElement(name, in_type.Type));

                        FlagForInsertion(valueToAdd, in_type.Type);

                        var ChildElem = System.Xml.Linq.XName.Get(in_type.ChildElementName);
                        foreach (var element in ChildrenElement.Elements(ChildElem))
                        {
                            if (element.Name != in_type.ChildElementName)
                                continue;

                            var elementName = element.Attribute("Name").Value;
                            var childValue = new AkWwiseProjectData.AkBaseInformation
                            {
                                Name = elementName,
                                Guid = new System.Guid(element.Attribute("ID").Value),
                            };
                            childValue.PathAndIcons.Add(new AkWwiseProjectData.PathElement(elementName, in_type.ChildType));
                            valueToAdd.values.Add(childValue);

                            FlagForInsertion(childValue, in_type.ChildType);
                        }

                        switch (in_type.Type)
                        {
                            case WwiseObjectType.StateGroup:
                                AkWwiseProjectInfo.GetData().StateWwu[in_wwuIndex].List.Add(valueToAdd);
                                break;

                            case WwiseObjectType.SwitchGroup:
                                AkWwiseProjectInfo.GetData().SwitchWwu[in_wwuIndex].List.Add(valueToAdd);
                                break;
                        }
                    }
                }
                break;

            default:
                UnityEngine.Debug.LogError("WwiseUnity: Unknown asset type in WWU parser");
                break;
        }
    }
}
#endif